#include "epoller.h"
#include "event.h"
#include <sys/epoll.h>
#include "tinyrpc/base/logger/logger.h"
#include <iostream>
namespace TinyRPC{

class Channel;

int create_efd(){
    int rt = epoll_create(128);
    return rt;
}
EPoller::EPoller()
:m_efd(create_efd())
, m_epollEvents(16){
    
}
void EPoller::addEvent(EventPtr event){
    epoll_event epollEvent;
    epollEvent.events = event->getEventOP();
    epollEvent.data.ptr = (void*) event.get();
    int rt = epoll_ctl(m_efd, EPOLL_CTL_ADD, event->getFd(), &epollEvent);
    if(rt < 0){
        exit(0);
    }

}
void EPoller::modifyEvent(EventPtr event){
    epoll_event epollEvent;
    epollEvent.events = event->getEventOP();
    epollEvent.data.ptr = (void*) event.get();
    epoll_ctl(m_efd, EPOLL_CTL_MOD, event->getFd(), &epollEvent);
}

void EPoller::deleteEvent(int fd){
    epoll_event epollEvent;
    epoll_ctl(m_efd, EPOLL_CTL_DEL, fd, &epollEvent);
}
void EPoller::poll(std::vector<Event*>& activateEvents){
    int num_activateEvents = epoll_wait(m_efd, &m_epollEvents[0], m_epollEvents.size(),-1);
    if(num_activateEvents == -1  ){
        if (errno != EINTR)
        {
            LOG_ERROR << "EPollPoller::poll() " <<strerror(errno);
            exit(0);
        }
    }
    fillActivateChannel(num_activateEvents, activateEvents);
    dynamicExpansion(num_activateEvents);
}

void EPoller::fillActivateChannel(int num_activateEvents, std::vector<Event*>& activateEvents){
    if(num_activateEvents <= 0){
        return;
    }
    activateEvents.reserve(num_activateEvents);
    for(int i=0; i<num_activateEvents;i++){
        epoll_event& epoll_event = m_epollEvents[i];
        Event* event = static_cast<Event*>(epoll_event.data.ptr);
        event->setRevents(epoll_event.events);
        activateEvents.push_back(event);
    }
}

void EPoller::dynamicExpansion(int num_activateEvents){
    int size = m_epollEvents.size();
    // 过小时缩容
    if(num_activateEvents < (size<<2)){
        m_epollEvents.reserve(m_epollEvents.size()<<2);
    }

    // 过大时扩容
    if(num_activateEvents == size){
        m_epollEvents.reserve(size*1.5);
    }
}
}

